﻿using System;
using System.Collections.Generic;
using SCG.SolarVengeanceEngine;
using SCG.General;

namespace SCG.SolarVengeance.Scenarios
{
    public class PsiWars : Scenario
    {
        //Large map
        public override int MapWidth
        {
            get
            {
                return 200;
            }
        }
        public override int MapHeight
        {
            get
            {
                return 200;
            }
        }

        //Create Scenario
        public override void BuildScenario(int numPlayers, int capitalValues, int startingResources)
        {
            //this string encodes which systems create RemoteViewers, and the value is passed to 
            //clients in multiplayer games.  The clients parse the string in the PostLoadInitialize method.
            string rvWorlds = "";

            _clusters.Clear();
            _rv.Clear();       

            //Create a cluster for each player
            for(int n = 0; n < numPlayers; n++)
            {
                int mindist = 60;
                int x, y;
                do
                {
                    x = Random(50, 150);
                    y = Random(50, 150);
                    mindist--;
                }
                while (!ClusterCoordsOK(x, y, mindist));
                _clusters.Add(new SCGPoint(x, y));
                CreateStarCluster(8, x, y, x, y, 20, 3);
                AssignCapital(Game.Players[n], new SCGRect(x - 20, y - 20, 40, 40));

                //Create a nebula there           
                CreateNebula(x + Random(-10, 10), y + Random(-10, 10), 1, 500);

                //and a pulsar
                int px, py;
                do
                {
                    px = Random(1, 200);
                    py = Random(1, 200);
                }
                while (Distance(px, py, x, y) > 20);
                CreatePulsar(px, py);

                //create wormholes
                for (int w = 0; w < 2; w++)
                {
                    int wx, wy;
                    do
                    {
                        wx = Random(1, 200);
                        wy = Random(1, 200);
                    }
                    while (Distance(wx, wy, x, y) > 20);
                    CreateWormhole(wx, wy, Random(10, 190), Random(10, 190));
                }

                //create fringe worlds (first is the RV world)
                for (int fringe = 0; fringe < 4; fringe++)
                {
                    int fx, fy;
                    do
                    {
                        fx = Random(1, 200);
                        fy = Random(1, 200);
                    }
                    while (!FringeCoordsOK(fx, fy, x, y));
                    StarSystem ss = CreateStarSystem(fx, fy, Random(1, 6), Random(1, 6), Random(1, 6), Random(1, 30));
                    if (fringe == 1)
                    {
                        ss.Owner = Game.Players[n];
                        rvWorlds += ss.Name + ";";
                        _rv.Add(ss);
                        _countdown[ss] = Random(100, 200);

                        //create initial RV's
                        for (int rv = 0; rv < 4; rv++)
                            CreateStarShip(fx, fy, Game.Players[n], StarShipType.RemoteViewer, 3, Random(10, 30), false);                        
                    }
                }
            }

            //Create black holes
            int bh = Random(3, 6);
            int bx, by;
            while (bh > 0)
            {
                do
                {
                    bx = Random(1, 200);
                    by = Random(1, 200);
                }
                while (!ClusterCoordsOK(bx, by, 30));
                CreateBlackHole(bx, by, Random(5, 10));
                bh--;
            }

            //pass the information about which worlds create RV's to clients, and ensure its saved with the game.
            SetValue("RVWorlds", rvWorlds);
        }

        //initialization after loading a game - recall the starsystems that create RemoteViewers
        public override void ClientInitialize()
        { 	        
            _rv.Clear();
            string rvWorlds = GetValue("RVWorlds");
            string[] tokens = rvWorlds.Split(';');
            foreach(string name in tokens)
                if (name.Trim() != "")
                {
                    StarSystem ss = Game.FindStarSystem(name);
                    _rv.Add(ss);
                }         
        }

        //description
        public override string Description
        {
            get
            {
                return "Each Star Lord possesses a distant StarSystem where RemoteViewers are periodically born.  Finding and eliminating enemy Viewers could severely cripple an enemy Lord.";
            }
        }

        //Process impulse, countdown and build new RV's
        public override void ProcessImpulse(int impulse)
        {         
            foreach (StarSystem rv in _rv)
            {
                if (!_countdown.ContainsKey(rv))
                    _countdown[rv] = Random(100, 200);
                _countdown[rv]--;
                if (_countdown[rv] <= 0)
                {              
                    DynamicEvents.CreateStarShip(rv.X, rv.Y, rv.Owner, StarShipType.RemoteViewer, 3, Random(10, 30), false);
                    _countdown[rv] = Random(150, 200);
                }
            }
        }

        //Coordinates OK for a cluster?
        private bool ClusterCoordsOK(int x, int y, int dist)
        {
            foreach (SCGPoint pt in _clusters)
                if (Distance(pt.X, pt.Y, x, y) < dist)
                    return false;
            return true;
        }

        //Location OK for fringe world?
        private bool FringeCoordsOK(int x, int y, int cx, int cy)
        {
            double d = Distance(x, y, cx, cy);
            return (d > 20 && d < 50);
        }

        //private members
        private List<SCGPoint> _clusters = new List<SCGPoint>();
        private List<StarSystem> _rv = new List<StarSystem>();
        private Dictionary<StarSystem, int> _countdown = new Dictionary<StarSystem, int>();
    }
}
